#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
@author:Zx
@file: image_utils.py
@time: 2025/7/23  10:37
# @describe: 验证码图片
"""
import random
import string
import logging
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from datetime import datetime, timedelta
from flask import session


def generate_captcha():
    """生成验证码图片"""
    try:
        # 生成验证码文本
        captcha_text = ''.join(random.choices(
            string.ascii_uppercase + string.digits, k=4))

        # 存储到session
        session['captcha'] = {
            'text': captcha_text,
            'expires_at': datetime.now() + timedelta(minutes=5)
        }

        # 创建图片
        image = Image.new('RGB', (120, 40), color=(255, 255, 255))
        draw = ImageDraw.Draw(image)

        # 加载字体
        font = _load_font()

        # 绘制验证码文本
        for i, char in enumerate(captcha_text):
            x = 10 + i * 28 + random.randint(-3, 3)
            y = 5 + random.randint(-5, 5)
            draw.text(
                (x, y), char, font=font,
                fill=(
                    random.randint(0, 150),
                    random.randint(0, 150),
                    random.randint(0, 150)
                )
            )

        # 添加干扰元素
        _add_noise(draw, image.width, image.height)

        # 输出图片
        buf = BytesIO()
        image.save(buf, 'png', quality=75)
        buf.seek(0)
        return buf
    except Exception as e:
        logging.error(f"生成验证码失败: {str(e)}", exc_info=True)
        return _generate_error_image()


def _load_font():
    """加载字体文件"""
    font_paths = [
        'arial.ttf',
        '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
        '/System/Library/Fonts/SFNS.ttf',
        'C:/Windows/Fonts/arial.ttf'
    ]

    for path in font_paths:
        try:
            return ImageFont.truetype(path, 24)
        except (IOError, OSError):
            continue

    logging.warning("使用默认字体，验证码可能不易识别")
    return ImageFont.load_default()


def _add_noise(draw, width, height):
    """添加干扰元素"""
    # 干扰线
    for _ in range(5):
        draw.line(
            [
                random.randint(0, width),
                random.randint(0, height),
                random.randint(0, width),
                random.randint(0, height)
            ],
            fill=(
                random.randint(100, 255),
                random.randint(100, 255),
                random.randint(100, 255)
            ),
            width=1
        )

    # 干扰点
    for _ in range(100):
        draw.point(
            [random.randint(0, width), random.randint(0, height)],
            fill=(
                random.randint(150, 255),
                random.randint(150, 255),
                random.randint(150, 255)
            )
        )


def _generate_error_image():
    """生成错误提示图片"""
    image = Image.new('RGB', (120, 40), color=(255, 255, 255))
    draw = ImageDraw.Draw(image)
    draw.text((10, 10), "ERROR", fill=(255, 0, 0))
    buf = BytesIO()
    image.save(buf, 'png')
    buf.seek(0)
    return buf